package network

import (
	"encoding/json"
)

// Serialize serializes ReplicaMessage to bytes
func (r *ReplicaMessage) Serialize() ([]byte, error) {
	jsons, err := json.Marshal(r)
	if err != nil {
		return []byte(""), err
	}
	return jsons, nil
}

// DeserializeReplicaMessage deserializes bytes to ReplicaMessage
func DeserializeReplicaMessage(input []byte) ReplicaMessage {
	var replicaMessage = new(ReplicaMessage)
	json.Unmarshal(input, &replicaMessage)
	return *replicaMessage
}

// SerializeWithMAC serializes message with MAC signature
func SerializeWithMAC(id int64, dest int64, msg []byte) ([]byte, error) {
	request := MessageWithSignature{
		Msg: msg,
		Sig: GenMAC(id, msg),
	}

	requestSer, err := json.Marshal(request)
	if err != nil {
		return []byte(""), err
	}
	return requestSer, err
}

// DeserializeMessageWithSignature deserializes MessageWithSignature
func DeserializeMessageWithSignature(input []byte) (MessageWithSignature, error) {
	var messageWithSignature = new(MessageWithSignature)
	err := json.Unmarshal(input, &messageWithSignature)
	return *messageWithSignature, err
}

// ConvertMessageToReplicaMessage converts Message to ReplicaMessage
func ConvertMessageToReplicaMessage(msg Message) ReplicaMessage {
	// Map Message Tag to TypeOfMessage
	var mtype TypeOfMessage
	// CBR messages use CBR_ALL
	if msg.Tag == "CBR" || msg.Tag == "CBR_PREPARE" || msg.Tag == "CBR_SHARE_REDUCE" || 
	   msg.Tag == "CBR_PROACTIVIZE" || msg.Tag == "CBR_SHARE_DIST" {
		mtype = CBR_ALL
	} else {
		mtype = CBR_ALL // Default to CBR
	}

	return ReplicaMessage{
		Mtype:    mtype,
		Instance: 0, // Could use Round if needed
		Source:   int64(msg.Sender),
		Round:    msg.Round,
		Payload:  msg.Payload,
	}
}

// ConvertReplicaToMessage converts ReplicaMessage to Message
func ConvertReplicaToMessage(replicaMsg ReplicaMessage, senderID int) Message {
	// Map TypeOfMessage back to Tag
	var tag string
	switch replicaMsg.Mtype {
	case CBR_ALL:
		tag = "CBR"
	case RBC_ALL, RBC_SEND, RBC_ECHO, RBC_READY:
		tag = "RBC"
	case ABA_ALL, ABA_BVAL, ABA_AUX, ABA_CONF, ABA_FINAL:
		tag = "ABA"
	case PRF:
		tag = "PRF"
	case MVBA_DISTRIBUTE:
		tag = "MVBA"
	default:
		tag = "CBR" // Default to CBR
	}

	return Message{
		Tag:     tag,
		Round:   replicaMsg.Round,
		Sender:  senderID,
		To:      -1, // Broadcast
		Payload: replicaMsg.Payload,
	}
}

